查看原文
其他

java程序员模板设计模式真的有必要掌握下,冗余代码一扫光

我是程序汪 我是程序汪 2021-09-08



程序汪公司项目实际代码中用的最频繁的设计模式就是模板设计模式了

下面就用具体代码例子去演示下模板设计模式的威力和优雅

什么场景可以用到模板模式

  • 需要固定算法骨架

  • 各个子类中具有公共部分

  • 需要控制子类扩展情况,扩展留给子类



<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>17.0</version></dependency>


代码目录

  • 模板类

  • 内部接口(回调关键)

  • 请求结果基类

  • 客户端代码


import com.google.common.base.Stopwatch;import designpattern.template.exception.BizRuntimeException;import java.util.concurrent.TimeUnit;


核心模板类型

这里用到的知识点有

  • 泛型的继承

  • 接口(入参是接口用于回调),父类引用指向子类实现

  • 异常


这个模板类就是所谓的骨架

固定的处理逻辑在这里写好

子类(就是哪个接口留着扩展)

BizHandle这个接口可以根据自己业务具体情况增加或删除


public class CxwBizTemplate {
public <RES extends BaseResult,REQ extends BaseRequest> RES process(RES result,                 REQ request,                 BizHandle bizHandle) Stopwatch stopWatch=Stopwatch.createStarted(); try{ bizHandle.preHandle(); bizHandle.handle(); }catch (BizRuntimeException e){ //把自定义的异常码封装 result } catch (Exception e){ bizHandle.handleException(e,result); System.out.println(e.getMessage()); }finally { //记录性能日志或统一处理 result System.out.println(bizHandle.desc()+" 耗时:" +stopWatch.elapsed(TimeUnit.SECONDS)); } return null; }
public interface BizHandle<RES>{        //前置处理 void preHandle();        //具体逻辑 void handle();        //功能描述 String desc();        //异常处理 void handleException(Throwable e,RES result); }}



下面是请求对象和返回结果对象,

程序汪公司项目中一般都是封装一个基类

然后子类继承的

公司一般基类都是 Base开头命名


特别注意结果基类一般都会设计有异常码、异常描述的

请求基类一般都会有 requestId 用来幂等控制的



class BaseRequest{ private String requestId; private String name; public String getRequestId() { return requestId; }
public void setRequestId(String requestId) { this.requestId = requestId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }};
//异常码定义在基类class BaseResult{
private String errorDesc; private String errorCode; public String getErrorDesc() { return errorDesc; }
public void setErrorDesc(String errorDesc) { this.errorDesc = errorDesc; }
public String getErrorCode() { return errorCode; }
public void setErrorCode(String errorCode) { this.errorCode = errorCode; }};



客户端调用代码

  • 匿名内部类(模板类里的接口类)


import com.google.common.base.Preconditions;public class CxwCustomer {
public static void main(String[] args) { CxwCustomer cxwCustomer=new CxwCustomer(); BaseRequest request=new BaseRequest(); cxwCustomer.query(request); }
public BaseResult query(BaseRequest request){ BaseResult result=new BaseResult(); CxwBizTemplate cxwBizTemplate=new CxwBizTemplate();        cxwBizTemplate.process(result, request, new CxwBizTemplate.BizHandle<BaseResult>() { @Override public void preHandle() { Preconditions.checkNotNull(request, "request参数空"); Preconditions.checkNotNull(request.getName(), "request name参数空"); Preconditions.checkNotNull(request.getRequestId(), "request RequestId参数空"); } @Override public void handle() { //TODO 你的业务代码 } @Override public String desc() { return "程序汪查询功能"; }
@Override public void handleException(Throwable e, BaseResult result) { result.setErrorDesc("程序汪查询异常"); } }); return null; }}




总结

  • 模板类就是写固定逻辑的地方

  • 注意模板类入参有一个钩子函数,上面例子就是接口

  • 钩子函数用于子类实现具体逻辑


使用场景

  • 一般Controller类某功能的增删改查,程序汪公司用的比较多 

  • rpc业务代码,程序汪手机移动端接口就是用的上面的代码

  • 其他微服务接口业务代码





和程序汪深度沟通可以去知识星球

程序汪往期精彩文章包含答案






程序汪最近整理的BAT大小厂面试题2019 (面试题目录推荐)

目录:我把精华文章都整理出来了

离职10天,面了4家公司,我的感受...

天真!这简历一看就是包装过的

思考,撸一段 SQL ? 还是写一段代码?

程序汪2019的总结,认识了很多朋友赚了些小钱,现在分享出来

给个[在看],是对程序汪最大的支持
: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存